package rexsee.multimedia;

import java.io.File;
import java.lang.reflect.Method;

import rexsee.core.browser.Browser;
import rexsee.core.browser.clazz.JavascriptInterface;
import rexsee.core.utilities.RexseeClazz;
import rexsee.core.utilities.Utilities;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.view.SurfaceHolder;

public class RexseeVideoCapture implements JavascriptInterface {

	public static final String INTERFACE_NAME = "VideoCapture";
	@Override
	public String getInterfaceName() {
		return mBrowser.application.resources.prefix + INTERFACE_NAME;
	}
	@Override
	public JavascriptInterface getInheritInterface(Browser childBrowser) {
		return this;
	}
	@Override
	public JavascriptInterface getNewInterface(Browser childBrowser) {
		return new RexseeVideoCapture(childBrowser);
	}

	public static final String EVENT_ONVIDEOCAPTUREINFO = "onVideoCaptureInfo";

	private final Browser mBrowser;
	private final MediaCaptureArguments mCaptureArguments;

	private SurfaceDialog mSurfaceDialog = null;
	private MediaRecorder mRecorder = null;

	private final MediaRecorder.OnErrorListener mErrorListener = new MediaRecorder.OnErrorListener() {
		@Override
		public void onError(MediaRecorder mr, int what, int extra) {
			mBrowser.exception(getInterfaceName(), "MEDIA_RECORDER_ERROR_UNKNOWN");
		}
	};
	private final MediaRecorder.OnInfoListener mInfoListener = new MediaRecorder.OnInfoListener() {
		@Override
		public void onInfo(MediaRecorder mr, int what, int extra) {
			String message;
			switch (what) {
				case MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED :
					message = "MEDIA_RECORDER_INFO_MAX_DURATION_REACHED";
					break;
				case MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED :
					message = "MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED";
					break;
				default :
					message = "MEDIA_RECORDER_INFO_UNKNOWN";
					break;
			}
			stop();
			mBrowser.eventList.run(EVENT_ONVIDEOCAPTUREINFO, new String[]{message});
		}
	};

	public RexseeVideoCapture(Browser browser) {
		mBrowser = browser;
		mCaptureArguments = new MediaCaptureArguments();
		mBrowser.eventList.add(EVENT_ONVIDEOCAPTUREINFO);
	}

	//JavaScript Interface

	//Start recording immediately with self-own preview dialog
	public boolean start(String path, String style) {
		final File target = Utilities.prepareWriteFile(path);
		if (target == null) {
			mBrowser.exception(getInterfaceName(), "Invalid target file path.");
			return false;
		}
		if (mSurfaceDialog != null) {
			mSurfaceDialog.dismiss();
			mSurfaceDialog = null;
		}
		RexseeCameraPreview preview = RexseeCameraPreview.getPreview(mBrowser);
		if (preview != null) preview.stop();
		try {
			mSurfaceDialog = new SurfaceDialog(mBrowser, style);
			mSurfaceDialog.start(new SurfaceHolder.Callback() {
				@Override
				public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
				}
				@Override
				public void surfaceCreated(SurfaceHolder holder) {
					try {
						mRecorder = mCaptureArguments.getRecorder(null, holder, mErrorListener, mInfoListener);
						mRecorder.setOutputFile(target.getAbsolutePath());
						mRecorder.prepare();
						mRecorder.start();
					} catch (Exception e) {
						if (mBrowser != null) mBrowser.exception(getInterfaceName(), e);
					}
				}
				@Override
				public void surfaceDestroyed(SurfaceHolder holder) {
					if (mRecorder != null) {
						try {
							mRecorder.stop();
							mRecorder.release();
						} catch (Exception e) {
						}
						mRecorder = null;
					}
				}
			});
			return true;
		} catch (Exception e) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName(), e);
			return false;
		}
	}
	//Start recording depends on the preview dialog started by ProfessionalCamera
	public boolean start(String path) {
		final File target = Utilities.prepareWriteFile(path);
		if (target == null) {
			mBrowser.exception(getInterfaceName(), "Invalid target file path.");
			return false;
		}
		RexseeCameraPreview preview = RexseeCameraPreview.getPreview(mBrowser);
		if (preview == null) {
			mBrowser.exception(getInterfaceName(), "Preview dialog is not ready, please call start(path,style) to start recording immediately or call " + mBrowser.application.resources.prefix + RexseeCameraPreview.INTERFACE_NAME + ".start(style) to start preview dialog.");
			return false;
		}
		if (mSurfaceDialog != null) {
			mSurfaceDialog.dismiss();
			mSurfaceDialog = null;
		}
		try {
			mRecorder = mCaptureArguments.getRecorder(preview.getCamera(), preview.previewDialog.surfaceView.getHolder(), mErrorListener, mInfoListener);
		} catch (Exception e) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName() + ".getRecorder", e);
			return false;
		}
		try {
			mRecorder.setOutputFile(target.getAbsolutePath());
		} catch (Exception e) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName() + ".setOutputFile", e);
			return false;
		}
		try {
			mRecorder.prepare();
		} catch (Exception e) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName() + ".prepare", e);
			return false;
		}
		try {
			mRecorder.start();
		} catch (Exception e) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName() + ".start", e);
			return false;
		}
		return true;
	}
	public boolean stop() {
		if (mSurfaceDialog != null) {
			mSurfaceDialog.dismiss();
			mSurfaceDialog = null;
		}
		RexseeCameraPreview preview = RexseeCameraPreview.getPreview(mBrowser);
		if (preview != null) {
			if (mRecorder != null) {
				try {
					mRecorder.stop();
					mRecorder.release();
				} catch (Exception e) {
				}
				mRecorder = null;
			}
			try {
				//preview.camera.reconnect();
				Method reconnect = RexseeClazz.getMethod(Camera.class, "reconnect");
				if (reconnect != null) reconnect.invoke(preview.getCamera());
				preview.getCamera().setPreviewDisplay(preview.previewDialog.surfaceView.getHolder());
			} catch (Exception e) {
				mBrowser.exception(getInterfaceName(), e);
				return false;
			}
		}
		return true;
	}

	public String getArguments() {
		return mCaptureArguments.toString(true);
	}
	public void setArguments(String argu) {
		mCaptureArguments.parseArguments(argu);
	}

}
